{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "2f4f0ea2-bc93-402a-b2d5-437c7e7b2c63",
   "metadata": {},
   "source": [
    "# Tracking speed - MLflow vs MLtraq\n",
    "\n",
    "In this experiment, we evaluate the tracking performance of MLFlow and MLtraq varying:\n",
    "\n",
    "* Number of experiments tracked\n",
    "* Number of runs tracked\n",
    "* Number of values tracked\n",
    "\n",
    "Results averaged on `10` runs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "7c810a1b-c63d-42a0-a7fb-9fd282eeb4c0",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-02-14T09:30:38.961101Z",
     "iopub.status.busy": "2024-02-14T09:30:38.960655Z",
     "iopub.status.idle": "2024-02-14T09:30:39.857203Z",
     "shell.execute_reply": "2024-02-14T09:30:39.856934Z"
    }
   },
   "outputs": [],
   "source": [
    "import uuid\n",
    "from contextlib import contextmanager, redirect_stderr, redirect_stdout\n",
    "from os import devnull\n",
    "\n",
    "import mlflow\n",
    "import mltraq\n",
    "\n",
    "\n",
    "@contextmanager\n",
    "def suppress_stdout_stderr():\n",
    "    \"\"\"A context manager that redirects stdout and stderr to devnull\"\"\"\n",
    "    with open(devnull, \"w\") as fnull:\n",
    "        with redirect_stderr(fnull) as err, redirect_stdout(fnull) as out:\n",
    "            yield (err, out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "2e0a231b-e4d7-4e2f-af21-1a9045791472",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-02-14T09:30:39.858838Z",
     "iopub.status.busy": "2024-02-14T09:30:39.858737Z",
     "iopub.status.idle": "2024-02-14T09:30:39.860713Z",
     "shell.execute_reply": "2024-02-14T09:30:39.860496Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "mlflow 2.10.2\n",
      "mltraq 0.0.115\n"
     ]
    }
   ],
   "source": [
    "# MLflow and MLtraq versions\n",
    "print(\"mlflow\", mlflow.__version__)\n",
    "print(\"mltraq\", mltraq.__version__)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "7440aa9f-ae50-440e-b682-253c3db1405d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-02-14T09:30:39.862048Z",
     "iopub.status.busy": "2024-02-14T09:30:39.861966Z",
     "iopub.status.idle": "2024-02-14T09:30:39.864175Z",
     "shell.execute_reply": "2024-02-14T09:30:39.863922Z"
    }
   },
   "outputs": [],
   "source": [
    "def test_mlflow(n_experiments=1, n_runs=1, n_values=1):\n",
    "    \"\"\"\n",
    "    Test MLflow tracking with a specified number of experiments, runs and values.\n",
    "    \"\"\"\n",
    "    mlflow.set_tracking_uri(\"sqlite:///:memory:\")\n",
    "    # MLflow does not recreate the SQLite db in memory if we set it again with\n",
    "    # set_tracking_uri . However, since the runs are executed in separate processes,\n",
    "    # every process triggers the recreation of the database.\n",
    "    for _ in range(n_experiments):\n",
    "        experiment_id = mlflow.create_experiment(str(uuid.uuid4()))\n",
    "        for _ in range(n_runs):\n",
    "            with mlflow.start_run(experiment_id=experiment_id):\n",
    "                for _ in range(0, n_values):\n",
    "                    mlflow.log_metric(key=\"value\", value=123)\n",
    "            mlflow.end_run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "5ed433c3-67bc-4c7f-922b-10d1ff1c592d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-02-14T09:30:39.865403Z",
     "iopub.status.busy": "2024-02-14T09:30:39.865320Z",
     "iopub.status.idle": "2024-02-14T09:30:39.867406Z",
     "shell.execute_reply": "2024-02-14T09:30:39.867201Z"
    }
   },
   "outputs": [],
   "source": [
    "def test_mltraq(n_experiments=1, n_runs=1, n_values=1):\n",
    "    \"\"\"\n",
    "    Test MLtraq tracking with a specified number of experiments, runs and values.\n",
    "    \"\"\"\n",
    "    session = mltraq.create_session()\n",
    "    for _ in range(n_experiments):\n",
    "        experiment = session.create_experiment()\n",
    "        for _ in range(n_runs):\n",
    "            with experiment.run() as run:\n",
    "                run.fields.value = []\n",
    "                for _ in range(0, n_values):\n",
    "                    run.fields.value.append(123)\n",
    "        experiment.persist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "802ac4e9-d8bc-4a45-b124-77113c7b37fe",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-02-14T09:30:39.868571Z",
     "iopub.status.busy": "2024-02-14T09:30:39.868498Z",
     "iopub.status.idle": "2024-02-14T09:32:16.401463Z",
     "shell.execute_reply": "2024-02-14T09:32:16.401069Z"
    }
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "31b53d5b80894537bbe15e35b4add5f5",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 1/540 [00:02<20:59,  2.34s/it]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "Experiment(name=\"rmtn92\", runs.count=540, id=\"b2f8b530-879b-4c23-ab4f-d8c7353c49d8\")"
      ],
      "text/plain": [
       "<mltraq.experiment.Experiment at 0x12dfae2f0>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def eval_time(run: mltraq.Run):\n",
    "    \"\"\"\n",
    "    Measure the time required to track a set of experiments.\n",
    "    \"\"\"\n",
    "\n",
    "    with suppress_stdout_stderr():\n",
    "        log = mltraq.Sequence()\n",
    "\n",
    "        # Warm up with creation of DB for MLflow, that\n",
    "        # given it uses Alembic to maintain the schema,\n",
    "        # it might be significantly slower.\n",
    "        test_mlflow(n_experiments=1, n_runs=1, n_values=1)\n",
    "\n",
    "        log.append(tag=\"begin\")\n",
    "        if run.params.method == \"MLflow\":\n",
    "            test_mlflow(\n",
    "                n_experiments=run.params.n_experiments,\n",
    "                n_runs=run.params.n_runs,\n",
    "                n_values=run.params.n_values,\n",
    "            )\n",
    "        elif run.params.method == \"MLtraq\":\n",
    "            test_mltraq(\n",
    "                n_experiments=run.params.n_experiments,\n",
    "                n_runs=run.params.n_runs,\n",
    "                n_values=run.params.n_values,\n",
    "            )\n",
    "        else:\n",
    "            raise Exception(\"unknown method\")\n",
    "\n",
    "        log.append(tag=\"end\")\n",
    "        durations = log.df().pivot_table(index=\"tag\", values=\"timestamp\")[\"timestamp\"]\n",
    "        run.fields.duration = (durations.end - durations.begin).total_seconds()\n",
    "        run.fields |= run.params\n",
    "\n",
    "\n",
    "e = mltraq.create_experiment()\n",
    "e.add_runs(\n",
    "    method=[\"MLflow\", \"MLtraq\"],\n",
    "    i=range(10),\n",
    "    n_experiments=[1, 10, 20],\n",
    "    n_runs=[1, 10, 20],\n",
    "    n_values=[1, 10, 20],\n",
    ")\n",
    "e.execute(eval_time)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "099da91f-1ebe-4fe2-a733-a45aaf148ab3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-02-14T09:32:16.407178Z",
     "iopub.status.busy": "2024-02-14T09:32:16.407019Z",
     "iopub.status.idle": "2024-02-14T09:32:17.490908Z",
     "shell.execute_reply": "2024-02-14T09:32:17.490534Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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dOgQrl27ph5BunjxIoKCgpCbm4uQkBD14TkA6NGjh0HikQqTJDI6np6eAIDLly/Dy8tLXX758mWEhYVJFJVxmTx5MrZt24a9e/fCx8dHXe7p6YmqqircvHlTYzTp8uXL6nal1mnixInqQ19SnVjSt29fTJs2DWfOnMGpU6fQq1cv5OXlISMjA8XFxejatStsbW0lia2laqr39d5kt9aIESPg5+eHlStXwtvbGyqVCkFBQSY9sZuH28joBAQEwNPTE+np6eqy0tJSHDp0qMX/KnlYQghMnjwZaWlp+OmnnxAQEKCxvkuXLrC0tNRou/z8fFy8eLHVt11rN2TIEFRVVaG6uhqRkZEGrz8wMBDHjh3TONMyKysLZmZm6NChAwAgODgYLi4umDdvHsLCwmBvb4++ffsiMzMTGRkZnI/UCA/7vlpaWqKmpuaB212/fh35+fl49913MWDAAAQGBqK4uFhjm8DAQBw/flzjLOSWfsIIR5IMrKysDGfPnlUvFxQUICcnB66urgY/LbMle1A7TZs2DfPmzUP79u0REBCA9957D97e3g1e76M1iI2NRUpKCv773//CwcFBPc/IyckJNjY2cHJywssvv4y4uDi4urrC0dERb775Jnr06IHu3btLHD1JydzcHLm5ueq/tSkpKalzFpKbmxsUCsUD6x87dixmz56N6OhoJCQk4OrVq3jzzTfx0ksvqecX1s5LWr9+vXpCb0hICCorK5Geno64uLiH2MPW6WHfV39/f6SnpyMiIgJyuRwuLi5a63BxcYGbmxtWrFgBLy8vXLx4EbNmzdLY5sUXX8Q777yDV199FfHx8Th//jw++eSTh99JKQkyqD179ggAdR7R0dFSh2ZUHtROKpVKvPfee8LDw0PI5XIxYMAAkZ+fL23QRkBbmwEQa9asUW9z+/Zt8cYbbwgXFxdha2srxowZI5RKpXRBk2Sio6PFqFGj6l0/atQo9XcuOjpa62fr5ZdfrrNtLQAiLS1NvXz8+HHRr18/YW1tLVxdXcWrr74q/vrrL43nLF68WAAQO3bs0IjDwsKizraknSHf1++++060a9dOWFhYCD8/PyGEELNnzxahoaF16t21a5cIDAwUcrlchISEiIyMjDqfgQMHDojQ0FBhZWUlwsLCxJYtWwQA8euvvxpm55uZTAghmiMZIyIiotbl/PnzCAgIwK+/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",
      "text/plain": [
       "<Figure size 600x400 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "from mltraq.utils.plot import bar_plot\n",
    "\n",
    "fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(figsize=[6, 4], nrows=2, ncols=2)\n",
    "fig.tight_layout()\n",
    "plt.subplots_adjust(hspace=0.4)\n",
    "\n",
    "bar_plot(\n",
    "    e.runs.df(),\n",
    "    x=\"n_experiments\",\n",
    "    x_label=\"Number of experiments\",\n",
    "    y=\"duration\",\n",
    "    group=\"method\",\n",
    "    yerr=True,\n",
    "    ax=ax1,\n",
    "    y_label=\"Duration (s)\",\n",
    "    y_lim={\"bottom\": 0},\n",
    "    y_grid=False,\n",
    ")\n",
    "\n",
    "bar_plot(\n",
    "    e.runs.df(),\n",
    "    x=\"method\",\n",
    "    x_label=\"Method\",\n",
    "    y=\"duration\",\n",
    "    yerr=True,\n",
    "    ax=ax2,\n",
    "    y_lim={\"bottom\": 0},\n",
    ")\n",
    "ax2.yaxis.label.set_visible(False)\n",
    "\n",
    "bar_plot(\n",
    "    e.runs.df(),\n",
    "    x=\"n_runs\",\n",
    "    x_label=\"Number of runs\",\n",
    "    y=\"duration\",\n",
    "    yerr=True,\n",
    "    y_label=\"Duration (s)\",\n",
    "    group=\"method\",\n",
    "    ax=ax3,\n",
    "    y_lim={\"bottom\": 0},\n",
    ")\n",
    "\n",
    "bar_plot(\n",
    "    e.runs.df(),\n",
    "    x=\"n_values\",\n",
    "    x_label=\"Number of values\",\n",
    "    y=\"duration\",\n",
    "    yerr=True,\n",
    "    group=\"method\",\n",
    "    ax=ax4,\n",
    "    y_label=\"duration (s)\",\n",
    "    y_lim={\"bottom\": 0},\n",
    ")\n",
    "ax4.yaxis.label.set_visible(False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ff2b0b57-292d-455a-ad53-3df33b35d588",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.6"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {
     "2c6f07c01fba423c889be90ea9348a75": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": "hidden",
       "width": null
      }
     },
     "31b53d5b80894537bbe15e35b4add5f5": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HBoxModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HBoxModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HBoxView",
       "box_style": "",
       "children": [
        "IPY_MODEL_d6b3e7f97e33489a9d2403dce874324d",
        "IPY_MODEL_431d43194eae409fa6b04d9325acbca9",
        "IPY_MODEL_87ab616162cf4c68ba75c47b19636d4a"
       ],
       "layout": "IPY_MODEL_2c6f07c01fba423c889be90ea9348a75",
       "tabbable": null,
       "tooltip": null
      }
     },
     "431d43194eae409fa6b04d9325acbca9": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "FloatProgressModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "FloatProgressModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "ProgressView",
       "bar_style": "",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_770e095718704c4d83ac380cffb0c1a3",
       "max": 540.0,
       "min": 0.0,
       "orientation": "horizontal",
       "style": "IPY_MODEL_ad87ec64931644aa9bea64dcbb0dd058",
       "tabbable": null,
       "tooltip": null,
       "value": 540.0
      }
     },
     "770e095718704c4d83ac380cffb0c1a3": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "781b04e56898487999098cf7368c59ec": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "background": null,
       "description_width": "",
       "font_size": null,
       "text_color": null
      }
     },
     "87ab616162cf4c68ba75c47b19636d4a": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_adc3e85796a84236ac7530e978291d43",
       "placeholder": "​",
       "style": "IPY_MODEL_b1603da9b0e84161bdb0067d63c65694",
       "tabbable": null,
       "tooltip": null,
       "value": " 540/540 [01:36&lt;00:00,  5.60it/s]"
      }
     },
     "ad87ec64931644aa9bea64dcbb0dd058": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "ProgressStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "ProgressStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "bar_color": null,
       "description_width": ""
      }
     },
     "adc3e85796a84236ac7530e978291d43": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "b1603da9b0e84161bdb0067d63c65694": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "background": null,
       "description_width": "",
       "font_size": null,
       "text_color": null
      }
     },
     "d3ae2e6f74744a98bb3411171bfe3505": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "d6b3e7f97e33489a9d2403dce874324d": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_d3ae2e6f74744a98bb3411171bfe3505",
       "placeholder": "​",
       "style": "IPY_MODEL_781b04e56898487999098cf7368c59ec",
       "tabbable": null,
       "tooltip": null,
       "value": "100%"
      }
     }
    },
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
